import os
import re
import sys
from invenio.config import CFG_WEBSUBMIT_BIBCONVERTCONFIGDIR
try:
	import libxml2
except:
	pass

def main(xml_file, template):
    pathname = os.path.abspath(template)
    path, script = os.path.split(pathname)
    if not os.path.exists(pathname):
        if os.path.exists(CFG_WEBSUBMIT_BIBCONVERTCONFIGDIR + "/" + script):
            path = CFG_WEBSUBMIT_BIBCONVERTCONFIGDIR
        else:
            raise Exception("Conversion script %s doesn't exist" % pathname)
    sys.path.append(path)
    try:
        convert = __import__(os.path.splitext(script)[0]).convert
    except ImportError:
        raise Exception("Conversion script must contain 'convert' function")
    return convert(xml_file)

class Record_set():
	
	def __init__(self):
		self.records = []

	def add_record(self, rec):
		self.records.append(rec)

	def to_xml(self):
		res = "<collection>\n"
		try:
			for record in self.records:
				res += record.to_xml(1)
			res += "</collection>"
		except AttributeError:
			for r in self.records:
				print r
			raise Exception("Wrong record set content")
		return res
		
	def parse(self, rs):
		doc = libxml2.parseDoc(rs)
		xctx = doc.xpathNewContext()
		for rec in xctx.xpathEval("//record"):
			newRec = Record()
			self.add_record(newRec.parse(str(rec)))
		doc.freeDoc()
		xctx.xpathFreeContext()
		return self

	def __str__(self):
		return "<Record_set object - %d records>" % len(self.records)
		
	def kill(self):
		for r in self.records:
			r.kill()
			del r


class Record():
	
	def __init__(self):
		self.fields = []
		
	def add_field(self, field):
		self.fields.append(field)
		
	def to_xml(self, level=0):
		indent = ""
		self.fields.sort(key=lambda x: x.tag)
		for r in range(level):
			indent += "\t"
		res = "%s<record>\n" % indent
		try:
			for field in self.fields:
				res += field.to_xml(level+1)
			res += "%s</record>\n" % indent
		except AttributeError:
			for f in self.fields:
				print f
			raise Exception("Wrong record content")
		return res
		
	def kill(self):
		for f in self.fields:
			f.kill()
			del f
		
	def parse(self, rec):
		doc = libxml2.parseDoc(rec)
		xctx = doc.xpathNewContext()
		xpath = xctx.xpathEval
		for cfield in xpath("//controlfield"):
			xctx.setContextNode(cfield)
			newCField = Controlfield(xpath("@tag")[0].content, cfield.content)
			self.add_field(newCField)
		xctx.setContextNode(doc)
		for field in xpath("//datafield"):
			xctx.setContextNode(field)
			newField = Field(xpath("@tag")[0].content, xpath("@ind1")[0].content, xpath("@ind2")[0].content)
			self.add_field(newField.parse(str(field)))
		doc.freeDoc()		
		xctx.xpathFreeContext()
		return self
		
	def get_fields(self, tag=None, ind1=None, ind2=None):
		res = [] 
		for field in self.fields:
			if isinstance(field, Field):
				if tag:
					if  tag == field.tag:
						pass
					else:
						continue
				if ind1:
					if ind1 == field.ind1:
						pass
					else:
						continue
				if ind2:
					if ind2 == field.ind2:
						pass
					else:
						continue
				res.append(field)
		return res
		
	def get_single_value(self, marc):
		if len(marc) == 6:
			tag = marc[:3]
			ind1 = marc[3]
			if ind1 == "_" or ind1 == "#":
				ind1 = " "
			ind2 = marc[4]
			if ind2 == "_" or ind2 == "#":
				ind2 = " "
			code = marc[5]
			field = self.get_fields(tag, ind1, ind2)
			if len(field) == 1:
				subfield = field[0].get_subfields(code)
				if len(subfield) == 1:
					return subfield[0].value
				elif len(subfield) == 0:
					return False
				else:
					raise Exception("Multiple subfields catched")
			elif len(field) == 0:
				return False
			else:
				raise Exception("Multiple fields catched")
		else:
			raise Exception("Wrong MARC")
		
	def get_controlfield(self, tag):
		res = None
		for field in self.fields:
			if isinstance(field, Controlfield):
				if tag == field.tag:
					res = field
					break
		return res
		
	def remove_field(self, field):
		if field in self.fields:
			self.fields.remove(field)
			return True
		else:
			return False
		
	def __str__(self):
		return "<Record object - %d fields>" % len(self.fields)
		
class Field():
	
	def __init__(self, tag, ind1=" ", ind2=" "):
		self.tag = tag
		self.ind1 = ind1
		self.ind2 = ind2
		self.subfields = []
		 
	def add_subfield(self, subfield):
		self.subfields.append(subfield)
		
	def to_xml(self, level=0):
		indent = ""
		for r in range(level):
			indent += "\t"
		res = '%s<datafield tag="%s" ind1="%s" ind2="%s">\n' % (indent, str(self.tag), str(self.ind1), str(self.ind2))
		subs = ""
		try:
			for subfield in self.subfields:
				subs += subfield.to_xml(level+1)
		except:
			print "Subfields..."
		if not subs:
			return ""
		res += subs
		res += "%s</datafield>\n" % indent
		return res
		
	def parse(self, field):
		doc = libxml2.parseDoc(field)
		xctx = doc.xpathNewContext()
		xpath = xctx.xpathEval
		for subfield in xpath("//subfield"):
			xctx.setContextNode(subfield)
			newSubfield = Subfield(xpath("@code")[0].content, subfield.content)
			self.add_subfield(newSubfield)
		doc.freeDoc()		
		xctx.xpathFreeContext()
		return self
		
	def get_subfields(self, code=None):
		res = []
		for subfield in self.subfields:
			if code:
				if code == subfield.code:
					pass
				else:
					continue
			res.append(subfield)
		return res
		
	def get_subfield(self, code):
		res = []
		for subfield in self.subfields:
			if code == subfield.code:
				res.append(subfield)
		if len(res) == 1:
			return res[0]
		elif len(res) == 0:
			return None
		else:
			raise Exception("Multiple subfields catched")
				
	def __str__(self):
		return '<Field object tag="%s" ind1="%s" ind2="%s" - %d subfields>' % (str(self.tag), str(self.ind1), str(self.ind2), len(self.subfields))
		
	def kill(self):
		for s in self.subfields:
			del s
		
class Controlfield():
	
	def __init__(self, tag, value):
		self.tag = tag
		self.value = value
		 
	def to_xml(self, level=0):
		indent = ""
		for r in range(level):
			indent += "\t"
		res = '%s<controlfield tag="%s">%s</controlfield>\n' % (indent, str(self.tag), str(self.value))
		return res
		
	def __str__(self):
		return '<Controlfield object tag="%s">' % (str(self.tag))
		
	def kill(self):
		pass
		
class Subfield():
	
	def __init__(self, code, value):
		self.code = code
		if not value:
			self.value = ""
		else:	
			if isinstance(value, list):
				value = value[0]
			if isinstance(value, libxml2.xmlNode) or isinstance(value, libxml2.xmlAttr):
				value = value.content 
			if isinstance(value, str):
				value = re.sub("&(?!\w+;)", "&amp;", value)
				value = re.sub("<", "&lt;", value)
				value = re.sub(">", "&gt;", value)
				self.value = value
			else:
				raise Exception("Invalid value type - " + str(type(value)))
			
				
	def to_xml(self, level=0):
		if not self.value:
			return ""
		indent = ""
		for r in range(level):
			indent += "\t"
		res = '%s<subfield code="%s">%s</subfield>\n' % (indent, str(self.code), str(self.value))
		return res
		
	def __str__(self):
		return '<Subfield object code="%s">' % self.code
		
